package com.sky.d_guava;

import java.util.concurrent.ExecutionException;

import org.junit.Test;

//import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

/**
 * guava 缓存
 * http://ifeve.com/google-guava-cachesexplained/
 * http://www.cnblogs.com/gongxijun/p/5781108.html
 * @Author:hjt
 */
public class ChacheDemo {
	/**
	Guava Cache适用于
		愿意消耗一些内存空间来提升速度
		预料到某些键会被查询一次以上
		缓存中存放的数据总量不会超出内存容量（单个应用运行时 本地缓存）
	
		1.get方法要么返回已经缓存的值，要么使用CacheLoader向缓存原子地加载新值
		2.CacheLoader.loadAll的实现可以为没有明确请求的键加载缓存值
		3.getAll(Iterable<? extends K>)方法用来执行批量查询
	默认情况下，对每个不在缓存中的键，getAll方法会单独调用CacheLoader.load来加载缓存项
		4.所有类型的Guava Cache，不管有没有自动加载功能，都支持get(K, Callable<V>)方法
		这个方法返回缓存中相应的值，或者用给定的Callable运算并把结果加入到缓存中
		模式"如果有缓存则返回；否则运算、缓存、然后返回"
		5.cache.put(key, value)方法可以直接向缓存中插入值，这会直接覆盖掉给定key之前映射的值
		
	缓存回收方式
		基于容量回收、定时回收和基于引用回收
		1.基于容量回收(size-based eviction)
			如果要规定缓存项的数目不超过固定值，只需要使用CacheBuilder.maximumSize(long)
			缓存将尝试回收最近没有使用或总体上很少使用的缓存项
			在缓存项的数目达到限定值之前，缓存就可能进行回收，一般发送在逼近限定值时
			不同的缓存有不同的“权重”(weights)
				CacheBuilder.weigher(Weigher)指定一个权重函数，
				CacheBuilder.maximumWeight(long)指定最大总重
			
		2.定时回收(Timed Eviction)
			expireAfterAccess(long, TimeUnit)：缓存项在给定时间内没有被读/写访问，则回收。
			请注意这种缓存的回收顺序和基于大小回收一样。
			expireAfterWrite(long, TimeUnit)：缓存项在给定时间内没有被写访问（创建或覆盖），则回收。
			如果认为缓存数据总是在固定时候后变得陈旧不可用，这种回收方式是可取的
	
		3.基于引用的回收(Reference-based Eviction)
			通过使用弱引用的键、或弱引用的值、或软引用的值，Guava Cache可以把缓存设置为允许垃圾回收
			
			CacheBuilder.weakKeys()：使用弱引用存储键。当键没有其它（强或软）引用时，缓存项可以被垃圾回收。
			因为垃圾回收仅依赖恒等式（==），使用弱引用键的缓存用==而不是equals比较键。
			
			CacheBuilder.weakValues()：使用弱引用存储值。当值没有其它（强或软）引用时，缓存项可以被垃圾回收。
			因为垃圾回收仅依赖恒等式（==），使用弱引用值的缓存用==而不是equals比较值。
			
			CacheBuilder.softValues()：使用软引用存储值。软引用只有在响应内存需要时，才按照全局最近最少使用的顺序回收。
			考虑到使用软引用的性能影响，我们通常建议使用更有性能预测性的缓存大小限定（见上文，基于容量回收）。
			使用软引用值的缓存同样用==而不是equals比较值。
	
	显示清除
		个别清除：Cache.invalidate(key)
		批量清除：Cache.invalidateAll(keys)
		清除所有缓存项：Cache.invalidateAll()
		
	移除监听器
		通过CacheBuilder.removalListener(RemovalListener)，可以声明一个监听器
		以便缓存项被移除时做一些额外操作。缓存项被移除时，RemovalListener会获取移除通知[RemovalNotification]
		包含移除原因[RemovalCause]、键和值
		
	
	 */

	@Test
	public void testDemo() throws Exception{
		
		//Cache实例通过CacheBuilder生成器模式生成的
		//LoadingCache是附带CacheLoader构建而成的缓存实现
		LoadingCache<String, String> cacheBuilder = CacheBuilder.newBuilder()
				.build(new CacheLoader<String, String>(){
					
					@Override
					public String load(String key) throws ExecutionException {
						String val = "hello," + key;
						return val;
					}
					
				});
		
		//Cache<K, V>
		System.out.println("jerry value:" + cacheBuilder.get("jerry"));
//		System.out.println("lisa value:" + cacheBuilder.apply("lisa"));
		cacheBuilder.put("harry", "harry poter");
		System.out.println("harry value:"+cacheBuilder.get("harry"));
		
		
	}
	
	
	
	
	
	@Test
	public void test() throws Exception{
		// TODO Auto-generated method stub

	}
}
